import json
import logging
from datetime import datetime
from typing import List
import sys
import pandas as pd
import requests

import constants as con
from entity.cbdata import CbData

# -------------------------- 2. 日志配置 --------------------------
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
logger = logging.getLogger("BondDataJsl")


# -------------------------- 3. 集思录配置 --------------------------


class JslConfig:

    def __init__(self):
        self.cb_referer = "https://www.jisilu.cn/web/data/cb/list"
        self.cb_api_path = "https://www.jisilu.cn/webapi/cb/list/"


# -------------------------- 5. 数据处理（核心：中文列名替换） --------------------------

class BondDataMapper:
    """
        self :表示这是类的方法，第一个参数必须是 self，代表类的实例
        data_list :类型注解，表示 data_list 应该是 CbData 对象组成的列表
        file_path: str = None: 如果不传，默认是 None，通常方法里会有逻辑给一个默认路径，比如 ./data.csv。
    """

    def save_to_csv_zh(self,
                       data_list: List[CbData], file_name,
                       file_path: str = None) -> None:
        try:
            # 1. 生成带日期的CSV文件名
            if not file_name:
                date_str = datetime.now().strftime("%Y%m%d")
                file_name = f"可转债(中文)_{date_str}.csv"
                # 1. 生成带日期的CSV文件名
            if not file_path:
                # 判断当前系统
                is_windows = sys.platform.startswith('win')
                is_linux = sys.platform.startswith('linux')
                if is_windows:
                    file_path = f"./jsl_data_en/{file_name}"
                if is_linux:
                    file_path = f"/root/jsl_data_en/{file_name}"

            # 2. 将CbData对象转换为字典列表 ，这个是对象的所有类实例都自带的属性，返回字典，key是属性名，value是属性值
            data_dict_list = [data.__dict__ for data in data_list]
            if not data_dict_list:
                logger.warning("无数据可保存")
                return
            # 3. 转换为DataFrame，并替换为中文列名（关键步骤）
            df = pd.DataFrame(data_dict_list)  # 这是使用pandas把字典转换？？？？？
            # 提取“英文→中文列名”的映射（从FIELD_MAPPING中取cn_name）
            # 生成的是一个字典 ，key是英文列名，value是中文列名
            cn_column_mapping = {
                en_field: info["cn_name"]
                for en_field, info in con.FIELD_MAPPING.items()
            }
            # 替换列名（只替换FIELD_MAPPING中存在的字段，其他字段保留原名）
            df.rename(columns=cn_column_mapping, inplace=True)  # 内置函数

            # 4. 调整列顺序（按FIELD_MAPPING的顺序排列中文列，更易读）
            cn_columns = [info["cn_name"]
                          for info in con.FIELD_MAPPING.values()]  # 中文列名列表
            # 过滤掉df中不存在的列（避免KeyError）
            valid_cn_columns = [col for col in cn_columns if col in df.columns]
            # 剩余未在FIELD_MAPPING中的列（如集思录新增字段）
            other_columns = [
                col for col in df.columns if col not in valid_cn_columns
            ]
            # 最终列顺序：中文映射列 + 其他列
            df = df[valid_cn_columns + other_columns]

            # 5. 保存CSV（utf-8-sig解决中文乱码）
            df.to_csv(file_path, index=False, encoding="utf-8-sig", na_rep="")

            # 6. 日志提示
            logger.info(f"✅ 中文表头CSV已保存：{file_path}")
            logger.info(f"📊 数据量：{len(df)} 条，中文列数：{len(valid_cn_columns)} 个")
            print(f"\n✅ 保存成功！CSV文件：{file_path}")
        except Exception as e:
            error_msg = f"❌ 保存CSV失败：{str(e)}"
            logger.error(error_msg)
            print(f"\n{error_msg}")

    def generate_field_doc(self, doc_path: str = "中文字段说明文档.csv") -> None:
        """可选：生成字段说明文档（英文+中文+含义），方便后续查阅"""
        field_doc = []
        for en_field, info in con.FIELD_MAPPING.items():
            field_doc.append({
                "英文字段名": en_field,
                "中文列名": info["cn_name"],
                "字段说明": info["desc"]
            })
        # 保存为CSV文档
        df_doc = pd.DataFrame(field_doc)
        df_doc.to_csv(doc_path, index=False, encoding="utf-8-sig")
        logger.info(f"✅ 字段说明文档已保存：{doc_path}")

    def save_to_csv_en(self, data_list: List[CbData], file_name, file_path: str = None) -> None:
        """
        将CbData对象列表保存为CSV文件
        :param data_list: CbData对象列表

        :param file_path: 保存路径（默认当前目录）
        """
        try:

            # 1. 生成带日期的CSV文件名
            if not file_name:
                date_str = datetime.now().strftime("%Y%m%d")
                file_name = "jsl_bond_data_" + date_str + ".csv"

                # 1. 生成带日期的CSV文件名
            if not file_path:

                # 判断当前系统
                is_windows = sys.platform.startswith('win')
                is_linux = sys.platform.startswith('linux')
                print(sys.platform)
                if is_windows:
                    file_path = f"./jsl_data/{file_name}"
                if is_linux:
                    file_path = f"/root/jsl_data/{file_name}"

            # 1. 将CbData对象列表转换为Python字典列表（Pandas可识别格式）
            # 遍历每个CbData对象，取其__dict__属性（包含所有字段）
            data_dict_list = [data.__dict__ for data in data_list]

            # 2. 转换为Pandas DataFrame（方便处理空值、格式）
            df = pd.DataFrame(data_dict_list)

            # 3. 保存为CSV（encoding="utf-8-sig"支持中文显示，index=False不保存行号）
            df.to_csv(file_path, index=False, encoding="utf-8-sig")

            logger.info(f"✅ 数据已成功保存到CSV文件：{file_path}")


        except Exception as e:
            error_msg = f"❌ 保存CSV文件失败：{str(e)}"
            logger.error(error_msg)
            print(f"\n{error_msg}")


# -------------------------- 6. 数据获取（复用你已有的逻辑） --------------------------


class BondDataJsl:

    def __init__(self):
        self.jsl_config = JslConfig()
        self.cb_data_mapper = BondDataMapper()
        self.session = requests.Session()

    def get_data(self, cookies: str) -> List[CbData]:
        try:
            # 1. 构造请求头（与之前一致）
            headers = {
                "Accept":
                    "application/json, text/plain, */*",
                "Accept-Encoding":
                    "gzip, deflate, br, zstd",
                "Accept-Language":
                    "en,en-GB;q=0.9,en-US;q=0.8,zh-CN;q=0.7,zh;q=0.6",
                "Cookie":
                    cookies,
                "Init":
                    "1",
                "Priority":
                    "u=1, i",
                "Referer":
                    self.jsl_config.cb_referer,
                "Sec-Ch-Ua":
                    "\"Google Chrome\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\"",
                "Sec-Ch-Ua-Mobile":
                    "?0",
                "Sec-Ch-Ua-Platform":
                    "\"Windows\"",
                "Sec-Fetch-Dest":
                    "empty",
                "Sec-Fetch-Mode":
                    "cors",
                "Sec-Fetch-Site":
                    "same-origin",
                "User-Agent":
                    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
            }

            # 2. 拼接带时间戳的URL（避免缓存）
            timestamp = int(datetime.now().timestamp() * 1000)
            full_url = f"{self.jsl_config.cb_api_path}?___t={timestamp}"

            # 3. 发送请求
            response = self.session.get(full_url, headers=headers, timeout=15)
            if response.status_code != 200:
                logger.error(f"请求失败，状态码：{response.status_code}")
                return []

            # 4. 解析数据
            json_data = json.loads(response.text)
            raw_data_list = json_data.get("data", [])  # 可转债数据
            if not raw_data_list:
                logger.info("未获取到数据")
                return []

            # 5. 转换为CbData对象列表
            cb_data_list = []
            for raw_data in raw_data_list:
                if raw_data.get("bond_id"):  # 过滤无效数据
                    cb_data = CbData(raw_data)  # 直接给这个类转为对象
                    cb_data_list.append(cb_data)

            logger.info(f"✅ 成功获取 {len(cb_data_list)} 条可转债数据")
            return cb_data_list

        except Exception as e:
            logger.error(f"获取数据异常：{str(e)}")
            return []


# -------------------------- 7. 示例调用 --------------------------
if __name__ == "__main__":
    # 替换为你的集思录Cookie
    JSL_COOKIES = ""

    # 执行流程：获取数据 → 保存中文表头CSV → 生成字段说明文档
    fetcher = BondDataJsl()
    cb_data_list = fetcher.get_data(cookies=JSL_COOKIES)
    if cb_data_list:
        # 1. 保存中文表头的CSV
        fetcher.cb_data_mapper.save_to_csv_zh(cb_data_list)
        # 2. 生成字段说明文档（可选，方便查阅）
        fetcher.cb_data_mapper.generate_field_doc()
